import { IVec3Like, Mat4, Quat, Rect, Vec2, Vec3 } from "cc"

export class MathUtils {

    static distance(x1: number, y1: number, x2: number, y2: number) {
        return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2))
    }

    /**随机返回正数或负数 */
    static randomSign(num: number) {
        return num * (Math.random() > 0.5 ? 1 : -1)
    }

    /**角度转弧度 */
    static angleToRadian(angle: number) {
        return angle * Math.PI / 180
    }

    /**向量转换为角度 */
    static vectorToAngle(v:IVec3Like) {
        return (Math.atan2(v.y, v.x) * 180 / Math.PI) || 0
    }


    /**弧度转360度内的角度 */
    static radianToAngleIn360(radian: number) {
        const angle = (radian * 180 / Math.PI) % 360
        if (angle < 0) {
            return angle + 360
        }
        return angle
    }



    /**计算两个向量的夹角 */
    static angleBetweenVectors(v1: Vect3, v2: Vect3) {
        return Math.acos( Vect3.dot(v1, v2) / (Vect3.mag(v1) * Vect3.mag(v2))) * 180 / Math.PI
    }
    /**获取指定方向上的矩形
     * @param position 起始点
     * @param direction 方向
     * @param width 矩形宽度
     * @param height 矩形高度
     * @param out 输出矩形
     * @returns 输出矩形
     */
    static getRectInDirection(position: Vec2 | IVec3Like, direction: Vec2 | IVec3Like, width: number, height: number, out: Rectangle): Rectangle {
        const normalizedDirection = direction;
        const rectCenter = {
            x: position.x + normalizedDirection.x * width / 2,
            y: position.y + normalizedDirection.y * height / 2
        };

        if (out) {
            out.x = rectCenter.x - width / 2
            out.y = rectCenter.y - height / 2
            out.width = width
            out.height = height
        } else {
            out = new Rectangle(
                rectCenter.x - width / 2,
                rectCenter.y - height / 2,
                width,
                height
            )
        }
        return out
    }
    /**归一化向量 */
    static normalizeVector(vector: Vec2 | Vec3): Vec2 {
        const magnitude = Math.sqrt(vector.x * vector.x + vector.y * vector.y);
        return {
            x: vector.x / magnitude,
            y: vector.y / magnitude
        } as any;
    }

    /**b向量在a向量右边 */
    static isRight(vectorA: Vect3, vectorB: Vect3): boolean {
        const crossProduct = vectorA.x * vectorB.y - vectorA.y * vectorB.x;

        if (crossProduct < 0) {
            return true
        } else {
            return false
        }
    }
    /**小数点保留n位,默认10位 */
    static fixNumber(num: number, n: number = 10) {
        return Math.round(num * Math.pow(10, n)) / Math.pow(10, n)
    }
    /**小数点保留n位 */
    static fixVec3(vec: { x?: number, y?: number, z?: number }, n: number = 10): any {
        for (const key in vec) {
            vec[key] = this.fixNumber(vec[key], n);
        }
        return vec
    }


    /**计算坐标点到线段的的直线距离 */
    static getDistanceToLine(point: IVec3Like, lineStart: IVec3Like, lineEnd: IVec3Like) {
        // let line = Vec3.subtract(new Vec3(),lineEnd,lineStart)
        // let pointToLine = Vec3.subtract(new Vec3(),point,lineStart)
        // let lineLen = line.length();
        // let pointToLineLen = pointToLine.length();
        // return Math.abs(line.dot(pointToLine) / lineLen);

        // 计算线段的方向向量
        const delta = {
            x: lineEnd.x - lineStart.x,
            y: lineEnd.y - lineStart.y,
            z: lineEnd.z - lineStart.z
        };

        // 计算点到线段起点的向量
        const fromPointToStart = {
            x: point.x - lineStart.x,
            y: point.y - lineStart.y,
            z: point.z - lineStart.z
        };

        // 计算点到线段的投影点
        const t = (fromPointToStart.x * delta.x + fromPointToStart.y * delta.y + fromPointToStart.z * delta.z) / (delta.x * delta.x + delta.y * delta.y + delta.z * delta.z);

        // 当t小于0时，投影点在线段起点的延长线上
        // 当t大于1时，投影点在线段终点的延长线上
        // 否则，投影点在线段上
        const projectionPoint = {
            x: lineStart.x + t * delta.x,
            y: lineStart.y + t * delta.y,
            z: lineStart.z + t * delta.z
        };

        // 计算点到投影点的向量
        const fromProjectionToPoint = {
            x: point.x - projectionPoint.x,
            y: point.y - projectionPoint.y,
            z: point.z - projectionPoint.z
        };

        // 计算点到线段的距离，即点到投影点向量的模长
        return Math.sqrt(fromProjectionToPoint.x * fromProjectionToPoint.x +
            fromProjectionToPoint.y * fromProjectionToPoint.y +
            fromProjectionToPoint.z * fromProjectionToPoint.z);
    }

}


export class Vect3 {
    constructor(public x = 0, public y = 0, public z = 0) { }
    // set(xOrVec3: number | IVec3Like, y?: number, z?: number) {
    //     return Vec3.set(this, xOrVec3, y, z)
    // }

    static set(vec3: IVec3Like, xOrVec3: number | IVec3Like, y?: number, z?: number) {
        if (typeof xOrVec3 === 'number') {
            vec3.x = MathUtils.fixNumber(xOrVec3)
            vec3.y = MathUtils.fixNumber(y || 0)
            vec3.z = MathUtils.fixNumber(z || 0)
        } else {
            vec3.x = MathUtils.fixNumber(xOrVec3.x)
            vec3.y = MathUtils.fixNumber(xOrVec3.y || 0)
            vec3.z = MathUtils.fixNumber(xOrVec3.z || 0)
        }
        return vec3
    }

    static add(out: IVec3Like, a: IVec3Like, b: IVec3Like) {
        return MathUtils.fixVec3(Vec3.add(out, a, b))
    }

    static rotateZ(out: IVec3Like, a: IVec3Like, b: IVec3Like, radian: number) {
        return MathUtils.fixVec3(Vec3.rotateZ(out, a, b, radian))
    }

    static subtract(out: IVec3Like, a: IVec3Like, b: IVec3Like) {
        return MathUtils.fixVec3(Vec3.subtract(out, a, b))
    }

    static multiplyScalar(out: IVec3Like, a: IVec3Like, b: number) {
        return MathUtils.fixVec3(Vec3.multiplyScalar(out, a, b))
    }

    static dot(a: IVec3Like, b: IVec3Like) {
        return MathUtils.fixNumber(Vec3.dot(a, b))
    }

    static mag(vec3: IVec3Like) {
        return MathUtils.fixNumber(Vec3.len(vec3))
    }

    static normalize(out: IVec3Like, a: IVec3Like) {
        return MathUtils.fixVec3(Vec3.normalize(out, a))
    }

    static distance(a: IVec3Like, b: IVec3Like) {
        return MathUtils.fixNumber(Vec3.distance(a, b))
    }

    static angle(a: IVec3Like, b: IVec3Like) {
        return MathUtils.fixNumber(Vec3.angle(a, b))
    }

    static cross(out: IVec3Like, a: IVec3Like, b: IVec3Like) {
        return MathUtils.fixVec3(Vec3.cross(out, a, b))
    }

    static project(out: IVec3Like, a: IVec3Like, b: IVec3Like) {
        return MathUtils.fixVec3(Vec3.project(out, a, b))
    }

    static negate(out: IVec3Like, a: IVec3Like) {
        return MathUtils.fixVec3(Vec3.negate(out, a))
    }

    static transformMat4(out: IVec3Like, a: IVec3Like, b: Mat4) {
        return MathUtils.fixVec3(Vec3.transformMat4(out, a, b))
    }

    static transformQuat(out: IVec3Like, a: IVec3Like, b: Quat) {
        return MathUtils.fixVec3(Vec3.transformQuat(out, a, b))
    }

    static lerp(out: IVec3Like, a: IVec3Like, b: IVec3Like, t: number) {
        return MathUtils.fixVec3(Vec3.lerp(out, a, b, t))
    }

    static equals(a: IVec3Like, b: IVec3Like) {
        return Vec3.strictEquals(a, b)
    }

    static angleToRadian(angle: number) {
        return angle * Math.PI / 180
    }

    static scaleAndAdd(out: IVec3Like, a: IVec3Like, b: IVec3Like, scale: number) {
        return MathUtils.fixVec3(Vec3.scaleAndAdd(out, a, b, scale))
    }
    /**返回两个点之间的坐标位置 */
    static getPosBetweenTowPoint(out: Vect3, v1: Vect3, v2: Vect3) {
        return MathUtils.fixVec3(Vect3.set(out, v1.x + (v2.x - v1.x) / 2, v1.y + (v2.y - v1.y) / 2, v1.z + (v2.z - v1.z) / 2));
    }
    static ZERO = Vec3.ZERO


}

export class Rectangle extends Rect { }